﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;

namespace Mazeball
{
    internal class Grid : IRenderable
    {
        private GridCell[] _cells;
        public Rectangle Rectangle { get; private set; }
        private List<int> _emptyCells = new List<int>();
        public float CellSize { get; private set; }

        private readonly int _numRows;

        public int NumRows
        {
            get { return _numRows; }
        }

        private readonly int _numCols;

        public int NumCols
        {
            get { return _numCols; }
        }

        public Grid(int rows, int cols)
        {
            _numCols = cols;
            _numRows = rows;

            // Initialize grid
            _cells = new GridCell[_numRows*_numCols];

            for (var x = 0; x < _numCols; x++)
            {
                for (var y = 0; y < _numRows; y++)
                {
                    var index = y*_numCols + x;
                    _cells[index] = new GridCell(x, y);
                }
            }

            Reset();
        }

        void Reset()
        {
            var index = 0;
            foreach (var cell in _cells)
            {
                cell.Ball = null;
                _emptyCells.Add(index++);
            }
        }

        public GridCell GetCell(int x, int y)
        {
            return x >= 0 && x < _numCols && y >= 0 && y < _numRows ? _cells[y*_numCols + x] : null;
        }

        public GridCell GetHitCell(Point p)
        {
            var p1 = new Point(p.X - Rectangle.X, p.Y - Rectangle.Y);
            var cellw = (double) Rectangle.Width/_numRows;
            var ix = (int) (p1.X/cellw);
            var iy = (int) (p1.Y/cellw);
            return GetCell(ix, iy);
        }

        public void UpdateDims(Rectangle newClipRect)
        {
            var border = GameSettings.GridBorderWidth;
            var minDim = Math.Min(newClipRect.Width, newClipRect.Height);
            var acme = minDim - 2*border;
            CellSize = (float)acme/_numCols;
            var xpos = (int) ((newClipRect.Width - acme)*0.5);
            var ypos = (int) ((newClipRect.Height - acme)*0.5);
            Rectangle = new Rectangle(xpos, ypos, acme, acme);

            // update cell positions
            foreach (var cell in _cells)
            {
                cell.y = ypos + cell.Row*CellSize;
                cell.x = xpos + cell.Col*CellSize;
                //cell.Position = new Point((int) x,(int) y);
            }

#if DEBUG
            foreach (var cell in _cells)
            {
                var str = "row:" + cell.Row + " col:" + cell.Col + " x:" + cell.x + " y:" + cell.y;
                Debug.WriteLine(str);
            }
#endif
            Debug.WriteLine("end");
        }

        public void Render(Rectangle rect, Graphics g)
        {
            //var border = GameSettings.GridBorderWidth;
            //var size = Math.Min(rect.Width, rect.Height) - 2 * border;
            //var r = new Rectangle(border, border, size, size);
            UpdateDims(rect);

            var penSize = GameSettings.GridLineWidth;
            var pen = new Pen(Color.Black, penSize);
            g.DrawRectangle(pen, Rectangle);

            pen = new Pen(Color.Black, 2);

            var size = Rectangle.Width;
            var step = (float) size/_numRows;
            var left = Rectangle.Left;
            var right = Rectangle.Right;
            var top = Rectangle.Top;
            var bottom = Rectangle.Bottom;

            for (var row = 1; row < _numRows; row++)
            {
                var y = (int) (top + row*step);
                g.DrawLine(pen, left, y, right, y);
            }

            for (var col = 1; col < _numCols; col++)
            {
                var x = (int) (left + col*step);
                g.DrawLine(pen, x, top, x, bottom);
            }
        }

        public Ball AddRandomBall()
        {
            var random = new Random();
            var num = random.Next(0, _emptyCells.Count - 1);
            var index = _emptyCells[num];
            //var cell = _cells[index];
            Debug.Assert(index > 0 && index < _cells.Length);
            return AddBall(index);
        }

        public Ball AddBall(int index)
        {
            var cell = _cells[index];
            var brush = ColorManager.GetRandomBrush();
            cell.Ball = new Ball(brush, cell);
            _emptyCells.Remove(index);
            return cell.Ball;
        }


    }
}